import fs from "fs/promises";
import type { namedTypes } from "ast-types";
import { parse } from "recast";
import { initFilePath, initJsxFilePath } from "../consts";
import { compareNodes } from "../utils/compare-nodes";
import type { Config } from "../utils/create-config";

/**
 * Sets up the `.flowbite-react/init.tsx` file in the project.
 *
 * This function ensures the init.tsx file exists and is up-to-date with the current configuration.
 * It will create or update the file if needed.
 */
export async function setupInit(config: Config) {
  const content = `
/* eslint-disable */
// @ts-nocheck
// biome-ignore-all lint: auto-generated file

// This file is auto-generated by the flowbite-react CLI.
// Do not edit this file directly.
// Instead, edit the .flowbite-react/config.json file.

import { StoreInit } from "flowbite-react/store/init";
import React from "react";

export const CONFIG = {
  dark: ${config.dark},
  prefix: "${config.prefix}",
  version: ${config.version},
};

export function ThemeInit() {
  return <StoreInit {...CONFIG} />;
}

ThemeInit.displayName = "ThemeInit";
`.trim();

  const targetPath = config.tsx ? initFilePath : initJsxFilePath;
  const oldPath = config.tsx ? initJsxFilePath : initFilePath;

  try {
    let currentContent = "";
    try {
      currentContent = await fs.readFile(targetPath, "utf-8");
    } catch {
      console.log(`Creating ${targetPath} file...`);
      setTimeout(() => fs.writeFile(targetPath, content), 10);
    }

    if (currentContent) {
      const currentAst = removeReactImport(parse(currentContent));
      const newAst = removeReactImport(parse(content));

      if (!compareNodes(currentAst.program, newAst.program)) {
        console.log(`Updating ${targetPath} file...`);
        setTimeout(() => fs.writeFile(targetPath, content), 10);
      }
    }

    try {
      await fs.access(oldPath);
      console.log(`Removing ${oldPath} file...`);
      await fs.unlink(oldPath);
    } catch {
      // noop
    }
  } catch (error) {
    console.error(`Failed to update ${targetPath}:`, error);
  }
}

/**
 * Removes `import React from "react"` from the AST
 */
function removeReactImport(ast: namedTypes.File): namedTypes.File {
  if (ast?.program?.body) {
    ast.program.body = ast.program.body.filter(
      (node) =>
        !(
          node.type === "ImportDeclaration" &&
          "value" in node.source &&
          typeof node.source.value === "string" &&
          node.source.value === "react" &&
          node.specifiers?.[0]?.local?.name === "React"
        ),
    );
  }
  return ast;
}
